#include "IntegralHistSet.h"

#include <cmath>

//////////////////////////////////////////////////////////////////
// SplitSet Object												//
//////////////////////////////////////////////////////////////////

// Constructor for a partitioned data set.
SplitSet::SplitSet(GhostSet *g_set, float *f_vals, float thresh)
{
	// Create empty sets
	_left_set = GhostSet();
	_right_set = GhostSet();

	// Traverse the input set, check which side of the threshold
	// each image is on, and add it to the appropriate set.
	float* f_vals_p = f_vals;
	IntegralHistNode* temp = g_set->_head;
	while(temp)
	{
		// If the feature value is less than the threshold, add to 
		// the left set, else add to the right set.
		if((*f_vals_p) < thresh)
		{
			// Check if we are adding for the first time.
			if(_left_set._head)
			{
				_left_set._tail->next = new IntegralHistNode;
				_left_set._tail->next->_label = temp->_label;
				if(temp->_label)
					_left_set._pos++;
				else
					_left_set._neg++;
				if(temp->_hist)
					_left_set._tail->next->_hist = temp->_hist;
				_left_set._tail->next->next = NULL;
				_left_set._tail->next->previous = _left_set._tail;
				_left_set._tail = _left_set._tail->next;
				_left_set._n++;
			}
			else
			{
				_left_set._head = new IntegralHistNode;
				_left_set._head->_label = temp->_label;
				if(temp->_label)
					_left_set._pos++;
				else
					_left_set._neg++;
				if(temp->_hist)
					_left_set._head->_hist = temp->_hist;
				_left_set._head->next = NULL;
				_left_set._head->previous = NULL;
				_left_set._tail = _left_set._head;
				_left_set._n++;
			}
		}
		else
		{
			// Check if we are adding for the first time.
			if(_right_set._head)
			{
				_right_set._tail->next = new IntegralHistNode;
				_right_set._tail->next->_label = temp->_label;
				if(temp->_label)
					_right_set._pos++;
				else
					_right_set._neg++;
				if(temp->_hist)
					_right_set._tail->next->_hist = temp->_hist;
				_right_set._tail->next->next = NULL;
				_right_set._tail->next->previous = _right_set._tail;
				_right_set._tail = _right_set._tail->next;
				_right_set._n++;
			}
			else
			{
				_right_set._head = new IntegralHistNode;
				_right_set._head->_label = temp->_label;
				if(temp->_label)
					_right_set._pos++;
				else
					_right_set._neg++;
				if(temp->_hist)
					_right_set._head->_hist = temp->_hist;
				_right_set._head->next = NULL;
				_right_set._head->previous = NULL;
				_right_set._tail = _right_set._head;
				_right_set._n++;
			}
		}
		temp = temp->next;
		++f_vals_p;
	}
}

// Function which returns the information gain for a partitioned
// data set.
float SplitSet::InfoGain()
{
	float entropy_l = - (((float)_left_set._neg)/(float)(_left_set._neg + _left_set._pos))*log(((float)_left_set._neg)/(float)(_left_set._neg + _left_set._pos)) 
					  - (((float)_left_set._pos)/(float)(_left_set._neg + _left_set._pos))*log(((float)_left_set._pos)/(float)(_left_set._neg + _left_set._pos));
	float entropy_r = - (((float)_right_set._neg)/(float)(_right_set._neg + _right_set._pos))*log(((float)_right_set._neg)/(float)(_right_set._neg + _right_set._pos)) 
					  - (((float)_right_set._pos)/(float)(_right_set._neg + _right_set._pos))*log(((float)_right_set._pos)/(float)(_right_set._neg + _right_set._pos));
	float gain = -((float)(_left_set._n)/(float)(_left_set._n + _right_set._n))*entropy_l
				 -((float)(_right_set._n)/(float)(_left_set._n + _right_set._n))*entropy_r;
	return gain;
}